function f_exe_osc_comm()
{   #执行osc命令的函数
    declare fun_name
    fun_name="f_exe_osc_comm"
    _tools="${1}"
    F_str="$(awk '{print $1" "$2" "$3}' <<< "${line}")"
    sql="$(awk -F"${F_str}" '{print $2}' <<< "${line}"|sed 's/`/\\`/g;s/"/\\"/g')"

    f_check_diy_info "${_tools}" || true             #检查用户diy配置, 对应dbadb_alter_table_repl_time表

    f_check_table_and_disk_size "${_t_}" || return 0 #检查磁盘空间及表大小是否符合预设判断逻辑, 如果不符合就返回

    if [ "${_tools}x" == "gh-ostx" ]
    then
        #如果是ghost就多新建一个表, 避免ghost执行失败污染测试环境, 因为ghost失败后可能会使用pt重新跑
        #f_exe_sql_in_test_mysql "create table ${test_db}.${t_tmp}_ghost like ${test_db}.${t_tmp};" >> ${log_file}  
        f_init_ghost_opt
        osc_comm="timeout 120s gh-ost --host=${test_host} --port=${test_port} --user=${test_user} --password=${test_pass} --database=${test_db}"
        osc_comm="${osc_comm} --table=${_t_} --alter=\"${sql}\" ${osc_array[@]}"
        osc_comm_tmp="gh-ost --host=${test_host} --port=${test_port} --user=${test_user} --password=xxxxxx --database=${test_db}"
        osc_comm_tmp="${osc_comm_tmp} --table=${_t_} --alter=\"${sql}\" ${osc_array[@]}"
        osc_array+=("--throttle-control-replicas=${check_slave_repl_list}")  #如果是生产就判断延迟
    else
        f_init_ptosc_opt
        osc_comm="timeout 120s pt-online-schema-change --alter=\"${sql}\" ${osc_array[@]} -p${test_pass} h=${test_host},P=${test_port}"
        osc_comm="${osc_comm},u=${test_user},D=${test_db},t=${_t_},A=utf8"
        osc_comm_tmp="pt-online-schema-change --alter=\"${sql}\" ${osc_array[@]} -pxxxxxx h=${test_host},P=${test_port}"
        osc_comm_tmp="${osc_comm_tmp},u=${test_user},D=${test_db},t=${_t_},A=utf8"
        [ -n "${check_slave_repl_list}" ] && osc_array+=("${check_slave_repl_list}")  #如果是生产就判断延迟
    fi
    
    res_file="${res_log}.tmp"
    f_logging "COMMAND:${fun_name}" "本次改表在测试环境执行的操作 ] [ ${osc_comm_tmp}" "execute:${execute}"
    f_logging "REMAIND:${fun_name}" "如下是改表前的表结构 ] [ ${line}" "execute:${execute}" >/dev/null
    [ "${execute}x" == "0x" ] && f_exe_sql_in_test_mysql "show create table ${test_db}.${t_tmp}\G" >> ${log_file}
    f_logging "REMAIND:${fun_name}" "开始在测试环境改表操作" "execute:${execute}"
    if [ "${execute}x" == "0x" ]
    then
        eval ${osc_comm} > ${res_log_test} 2>&1 && osc_exe_state="${?}" || osc_exe_state="${?}"
    else
        osc_exe_state=0
    fi

    if [ ${osc_exe_state} -eq 0 ] && [ "${execute}x" == "0x" ]
    then
        f_logging "REMAIND:${fun_name}" "如下是改表后的表结构 ] [ ${line}" "execute:${execute}" >/dev/null
        f_exe_sql_in_test_mysql "show create table ${test_db}.${t_tmp}\G" >> ${log_file}
        f_logging "INFO:${fun_name}" "在测试环境 '${test_host}:${test_port}' 执行成功 ] [ ${line}" "execute:${execute}"
        f_check_table_after_ddl "${_t_}"
        if [ "${execute}x" != "1x" ]
        then
            {
                [ -f "${osc_run_mark_file}" ] && chattr -i ${osc_run_mark_file} && rm -f ${osc_run_mark_file}
                [ -f "${script_queue_file}" ] && rm -f "${script_queue_file}"
            } || true
            return 0
        fi
    elif [ ${osc_exe_state} -ne 0 ]
    then
        f_kill_osc_process "${_tools}" "${test_host}" "${test_port}" "${test_db}" "${_t_}" "${mysql_user}" || true
        if [ "${execute}x" != "1x" ]
        then
            {
                __="$(tail -100 ${res_log_test}|sed "s/${mysql_pass}/xxxxxx/g"|grep -iw "ERROR"|grep -v "\[info\]"\
                    |grep -P "^\d{4}-\d{2}-\d{2}"|grep -v "ERROR Maximal timeout is 10sec. Timeout remains at 3"|awk '{
                    for(i=3;i<=NF;i++){if(i==NF){printf $i;}else{printf $i" ";}}printf"\n"}' |awk '{if ((!a[$0]++)==1){
                    printf "\n\t'${t_tmp}' ERROR"NR" : "$0}}'|sed 's/, $//g')"
                grep -q "FATAL No shared unique key can be found after ALTER! Bailing out" ${res_log_test} && echo 3 > ${bug_mark_file}
                grep -q "To force this operation to continue, supply --allow-nullable-unique-key flag." ${res_log_test} && echo 4 > ${bug_mark_file}
                [ -f "${osc_run_mark_file}" ] && chattr -i ${osc_run_mark_file} && rm -f ${osc_run_mark_file}
                [ -f "${script_queue_file}" ] && rm -f "${script_queue_file}"
            } || true

            if [ -f "${bug_mark_file}" ]
            then
                __="测试环境执行不通过, 遇到ghost的限制"
                if [ "$(cat ${bug_mark_file})x" == "3x" ]
                then
                    f_logging "ERROR:${fun_name}" "${__}[FATAL No shared unique key can be found after ALTER!], 现在使用pt再次改表"
                elif [ "$(cat ${bug_mark_file})x" == "4x" ]
                then
                    f_logging "ERROR:${fun_name}" "${__}[To force this operation to continue, supply --allow-nullable-unique-key flag.], 现在使用pt再次改表"
                fi
                unset __ && return 100
            else
                declare grep_list
                grep_list="failed|--no-check-alter|--allow-nullable-unique|--alter-foreign-keys-method"
                [ -z "${__}" ] && __=$(tail -100 ${res_log_test}|sed "s/${mysql_pass}/xxxxxx/g"|grep -iwE "${grep_list}"|awk '{
                    for(i=1;i<=NF;i++){if(i==NF){printf $i;}else{printf $i" ";}}printf"\n"}' |awk '{if ((!a[$0]++)==1){
                    printf "\n\t'${t_tmp}' ERROR"NR" : "$0}}'|sed 's/, $//g')
                exe_sql_get_error_info_list+=("${__}] [ ${line}")
                return 0
            fi
        else
            f_record_info_to_dbadb "${_tools}" "${_t_}" "测试遇到未知失败. 详情请看${localhost_ip}:${res_log_test}" || true
            { tail -10 ${res_log_test}|tee -a ${log_file};} || true
            f_logging "ERROR:${fun_name}" "在测试环境 '${test_host}:${test_port}' 执行失败, 详情请看osc执行日志 '${res_log_test}' ] [ ${line}" "2" "1"
        fi
    fi

    f_logging "REMAIND:${fun_name}" "现在开始在 '${mysql_host}:${mysql_port}' 环境执行提交的改表语句"

    if [ "${_tools}x" == "gh-ostx" ]
    then
        osc_comm="gh-ost --host=${mysql_host} --port=${mysql_port} --user=${mysql_user} --password=${mysql_pass} --database=${mysql_db}"
        osc_comm="${osc_comm} --table=${_t_} --alter=\"${sql}\" ${osc_array[@]}"
        osc_comm_tmp="gh-ost --host=${mysql_host} --port=${mysql_port} --user=${mysql_user} --password=xxxxxx --database=${mysql_db}"
        osc_comm_tmp="${osc_comm_tmp} --table=${_t_} --alter=\"${sql}\" ${osc_array[@]}"
    else
        osc_comm="pt-online-schema-change --alter=\"${sql}\" ${osc_array[@]} -p${mysql_pass} h=${mysql_host},P=${mysql_port}"
        osc_comm="${osc_comm},u=${mysql_user},D=${mysql_db},t=${_t_},A=utf8"
        osc_comm_tmp="pt-online-schema-change --alter=\"${sql}\" ${osc_array[@]} -pxxxxxx h=${mysql_host},P=${mysql_port}"
        osc_comm_tmp="${osc_comm_tmp},u=${mysql_user},D=${mysql_db},t=${_t_},A=utf8"
    fi

    { f_check_mdl_lock_daemonize "${_tools}" "${_t_}" >> ${log_file} || true;} &

    { f_check_daemonize "${_tools}" "${_t_}" || true;} &

    f_logging "COMMAND:${fun_name}" "本次改表在线上环境执行的操作 ] [ ${osc_comm_tmp}"
    f_check_tmp_table "${_tools}" "${_t_}"
    f_logging "REMAIND:${fun_name}" "如下是改表前的表结构 ] [ ${line}" >/dev/null
    f_exe_sql_in_mysql "show create table ${_mysql_db_}.${t_tmp}\G" >> ${log_file}
    f_logging "REMAIND:${fun_name}" "开始在线上环境改表操作"
    [ -f "${gh_socket_file}" ] && rm -f "${gh_socket_file}"
    eval ${osc_comm} > ${res_log} 2>&1 && osc_exe_state="${?}" || osc_exe_state="${?}"
    f_logging "REMAIND:${fun_name}" "注 : 改表在线上环境执行结束, 但是不代表任务执行成功 ] [ ${line}"
    #改表任务结束, 删除标志文件, 这个文件删除以后检查mdl状态的任务基本就结束了(可能存在几秒延迟)
    { [ -f "${osc_run_mark_file}" ] && chattr -i ${osc_run_mark_file} && rm -f ${osc_run_mark_file};} || true

    f_logging "WARN:${fun_name}" "正在等待mdl检查任务结束(最长120秒), 如果需要手动终止检查mdl任务可以删除'${check_mdl_mark_file}'文件"
    for (( wait_time=0; wait_time<120; wait_time++ ))
    do  #等待检查mdl任务完成, 最多等待120s
        sleep 1
        [ ! -f "${check_mdl_mark_file}" -a ! -f "${check_connect_file}" ] && break
    done
    
    { 
        [ -f "${check_mdl_mark_file}" ] && rm -f ${check_mdl_mark_file}
        [ -f "${check_connect_file}" ] && rm -f ${check_connect_file}
    } || true

    f_logging "INFO:${fun_name}" "mdl检查任务完成"

    [ -f "${pause_file_name}" ] && osc_exe_state="-1"
    [ -f "${has_max_process_file}" ] && osc_exe_state="-2"

    if [ ${osc_exe_state} -ne 0 ] && [ ! -f "${has_mdl_lock_file}" ] && [ ! -f "${has_max_process_file}" ]
    then #清理临时表
        f_delete_tmp_table "${_tools}" "${mysql_db}" "${_t_}" "${mysql_host}" "原因是改表任务执行异常, 临时表未清理"
    fi

    if [ ${osc_exe_state} -eq 0 ]
    then
        f_logging "REMAIND:${fun_name}" "如下是改表后的表结构 ] [ ${line}" >/dev/null
        f_exe_sql_in_mysql "show create table ${_mysql_db_}.${t_tmp}\G" >> ${log_file}
        f_logging "INFO:${fun_name}" "在 '${mysql_host}:${mysql_port}' 环境执行提交的改表语句, 执行成功 ] [ ${line}"
    elif [ "${osc_exe_state}x" == "-1x" ]
    then
        f_record_info_to_dbadb "${_tools}" "${_t_}" "遇到mdl等待. 详情请看${localhost_ip}:${log_file}" "mail" "遇到mdl等待,改表终止 如有疑问请联系dba" || true
        f_logging "ERROR:${fun_name}" "在线上环境 '${mysql_host}:${mysql_port}' 遇到mdl等待, 终止任务, 详情请看 '${log_file}' ] [ ${line}" "2" "1"
    elif [ "${osc_exe_state}x" == "-2x" ] && [ "$(cat ${has_max_process_file})x" == "threadx" ]
    then
        f_record_info_to_dbadb "${_tools}" "${_t_}" "遇到活跃连接数过高. 详情请看${localhost_ip}:${log_file}" "mail" "活跃连接数过高,改表终止 如有疑问请联系dba" || true
        f_logging "ERROR:${fun_name}" "在线上环境 '${mysql_host}:${mysql_port}' 遇到活跃连接数过高, 终止任务 ] [ ${line}" "2" "1"
    elif [ "${osc_exe_state}x" == "-2x" ] && [ "$(cat ${has_max_process_file})x" == "connectx" ]
    then
        f_record_info_to_dbadb "${_tools}" "${_t_}" "遇到连接数过高. 详情请看${localhost_ip}:${log_file}" "mail" "连接数过高,改表终止 如有疑问请联系dba" || true
        f_logging "ERROR:${fun_name}" "在线上环境 '${mysql_host}:${mysql_port}' 遇到连接数过高, 终止任务 ] [ ${line}" "2" "1"
    else
        f_record_info_to_dbadb "${_tools}" "${_t_}" "遇到未知失败. 详情请看${localhost_ip}:${res_log}" || true
        tail -10 ${res_log}|grep -vP "^(Copy:)|(Terminated$)" || true
        __="$(tail -100 ${res_log}|sed "s/${mysql_pass}/xxxxxx/g"|grep -iw "ERROR"|tail -1) ] [ 在 '${mysql_host}:${mysql_port}' " || true
        f_logging "ERROR:${fun_name}" "${__}环境执行提交的改表语句, 执行失败, 详情请查看osc工具执行日志 '${res_log}' ] [ ${line}" "2"

        if [ "${_tools}x" != "gh-ostx" ] && [ "$(grep -c "^Successfully altered .${mysql_db}...${_t_}..$" ${res_log})x" == "1x" ]
        then #有时候执行完成但是返回状态码是非0
            f_logging "ERROR:${fun_name}" "可能实际已经改成功了, 但是命令返回状态是非0, 请前往环境进行检查确认!!!" "2"
        fi
        if [ -f "${bug_mark_file}" ]
        then
            return 100
        else
            f_exit "1"
        fi
    fi
    return 0
}

